home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / lib-tk / Tkdnd.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  13KB  |  361 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. """Drag-and-drop support for Tkinter.
  5.  
  6. This is very preliminary.  I currently only support dnd *within* one
  7. application, between different windows (or within the same window).
  8.  
  9. I an trying to make this as generic as possible -- not dependent on
  10. the use of a particular widget or icon type, etc.  I also hope that
  11. this will work with Pmw.
  12.  
  13. To enable an object to be dragged, you must create an event binding
  14. for it that starts the drag-and-drop process. Typically, you should
  15. bind <ButtonPress> to a callback function that you write. The function
  16. should call Tkdnd.dnd_start(source, event), where 'source' is the
  17. object to be dragged, and 'event' is the event that invoked the call
  18. (the argument to your callback function).  Even though this is a class
  19. instantiation, the returned instance should not be stored -- it will
  20. be kept alive automatically for the duration of the drag-and-drop.
  21.  
  22. When a drag-and-drop is already in process for the Tk interpreter, the
  23. call is *ignored*; this normally averts starting multiple simultaneous
  24. dnd processes, e.g. because different button callbacks all
  25. dnd_start().
  26.  
  27. The object is *not* necessarily a widget -- it can be any
  28. application-specific object that is meaningful to potential
  29. drag-and-drop targets.
  30.  
  31. Potential drag-and-drop targets are discovered as follows.  Whenever
  32. the mouse moves, and at the start and end of a drag-and-drop move, the
  33. Tk widget directly under the mouse is inspected.  This is the target
  34. widget (not to be confused with the target object, yet to be
  35. determined).  If there is no target widget, there is no dnd target
  36. object.  If there is a target widget, and it has an attribute
  37. dnd_accept, this should be a function (or any callable object).  The
  38. function is called as dnd_accept(source, event), where 'source' is the
  39. object being dragged (the object passed to dnd_start() above), and
  40. 'event' is the most recent event object (generally a <Motion> event;
  41. it can also be <ButtonPress> or <ButtonRelease>).  If the dnd_accept()
  42. function returns something other than None, this is the new dnd target
  43. object.  If dnd_accept() returns None, or if the target widget has no
  44. dnd_accept attribute, the target widget's parent is considered as the
  45. target widget, and the search for a target object is repeated from
  46. there.  If necessary, the search is repeated all the way up to the
  47. root widget.  If none of the target widgets can produce a target
  48. object, there is no target object (the target object is None).
  49.  
  50. The target object thus produced, if any, is called the new target
  51. object.  It is compared with the old target object (or None, if there
  52. was no old target widget).  There are several cases ('source' is the
  53. source object, and 'event' is the most recent event object):
  54.  
  55. - Both the old and new target objects are None.  Nothing happens.
  56.  
  57. - The old and new target objects are the same object.  Its method
  58. dnd_motion(source, event) is called.
  59.  
  60. - The old target object was None, and the new target object is not
  61. None.  The new target object's method dnd_enter(source, event) is
  62. called.
  63.  
  64. - The new target object is None, and the old target object is not
  65. None.  The old target object's method dnd_leave(source, event) is
  66. called.
  67.  
  68. - The old and new target objects differ and neither is None.  The old
  69. target object's method dnd_leave(source, event), and then the new
  70. target object's method dnd_enter(source, event) is called.
  71.  
  72. Once this is done, the new target object replaces the old one, and the
  73. Tk mainloop proceeds.  The return value of the methods mentioned above
  74. is ignored; if they raise an exception, the normal exception handling
  75. mechanisms take over.
  76.  
  77. The drag-and-drop processes can end in two ways: a final target object
  78. is selected, or no final target object is selected.  When a final
  79. target object is selected, it will always have been notified of the
  80. potential drop by a call to its dnd_enter() method, as described
  81. above, and possibly one or more calls to its dnd_motion() method; its
  82. dnd_leave() method has not been called since the last call to
  83. dnd_enter().  The target is notified of the drop by a call to its
  84. method dnd_commit(source, event).
  85.  
  86. If no final target object is selected, and there was an old target
  87. object, its dnd_leave(source, event) method is called to complete the
  88. dnd sequence.
  89.  
  90. Finally, the source object is notified that the drag-and-drop process
  91. is over, by a call to source.dnd_end(target, event), specifying either
  92. the selected target object, or None if no target object was selected.
  93. The source object can use this to implement the commit action; this is
  94. sometimes simpler than to do it in the target's dnd_commit().  The
  95. target's dnd_commit() method could then simply be aliased to
  96. dnd_leave().
  97.  
  98. At any time during a dnd sequence, the application can cancel the
  99. sequence by calling the cancel() method on the object returned by
  100. dnd_start().  This will call dnd_leave() if a target is currently
  101. active; it will never call dnd_commit().
  102.  
  103. """
  104. import Tkinter
  105.  
  106. def dnd_start(source, event):
  107.     h = DndHandler(source, event)
  108.     if h.root:
  109.         return h
  110.     else:
  111.         return None
  112.  
  113.  
  114. class DndHandler:
  115.     root = None
  116.     
  117.     def __init__(self, source, event):
  118.         if event.num > 5:
  119.             return None
  120.         
  121.         root = event.widget._root()
  122.         
  123.         try:
  124.             root._DndHandler__dnd
  125.             return None
  126.         except AttributeError:
  127.             root._DndHandler__dnd = self
  128.             self.root = root
  129.  
  130.         self.source = source
  131.         self.target = None
  132.         self.initial_button = button = event.num
  133.         self.initial_widget = widget = event.widget
  134.         self.release_pattern = '<B%d-ButtonRelease-%d>' % (button, button)
  135.         if not widget['cursor']:
  136.             pass
  137.         self.save_cursor = ''
  138.         widget.bind(self.release_pattern, self.on_release)
  139.         widget.bind('<Motion>', self.on_motion)
  140.         widget['cursor'] = 'hand2'
  141.  
  142.     
  143.     def __del__(self):
  144.         root = self.root
  145.         self.root = None
  146.         if root:
  147.             
  148.             try:
  149.                 del root._DndHandler__dnd
  150.             except AttributeError:
  151.                 pass
  152.             except:
  153.                 None<EXCEPTION MATCH>AttributeError
  154.             
  155.  
  156.         None<EXCEPTION MATCH>AttributeError
  157.  
  158.     
  159.     def on_motion(self, event):
  160.         x = event.x_root
  161.         y = event.y_root
  162.         target_widget = self.initial_widget.winfo_containing(x, y)
  163.         source = self.source
  164.         new_target = None
  165.         while target_widget:
  166.             
  167.             try:
  168.                 attr = target_widget.dnd_accept
  169.             except AttributeError:
  170.                 pass
  171.  
  172.             new_target = attr(source, event)
  173.             if new_target:
  174.                 break
  175.             
  176.             target_widget = target_widget.master
  177.         old_target = self.target
  178.         if old_target is new_target:
  179.             if old_target:
  180.                 old_target.dnd_motion(source, event)
  181.             
  182.         elif old_target:
  183.             self.target = None
  184.             old_target.dnd_leave(source, event)
  185.         
  186.         if new_target:
  187.             new_target.dnd_enter(source, event)
  188.             self.target = new_target
  189.         
  190.  
  191.     
  192.     def on_release(self, event):
  193.         self.finish(event, 1)
  194.  
  195.     
  196.     def cancel(self, event = None):
  197.         self.finish(event, 0)
  198.  
  199.     
  200.     def finish(self, event, commit = 0):
  201.         target = self.target
  202.         source = self.source
  203.         widget = self.initial_widget
  204.         root = self.root
  205.         
  206.         try:
  207.             del root._DndHandler__dnd
  208.             self.initial_widget.unbind(self.release_pattern)
  209.             self.initial_widget.unbind('<Motion>')
  210.             widget['cursor'] = self.save_cursor
  211.             self.target = None
  212.             self.source = None
  213.             self.initial_widget = None
  214.             self.root = None
  215.             if target:
  216.                 if commit:
  217.                     target.dnd_commit(source, event)
  218.                 else:
  219.                     target.dnd_leave(source, event)
  220.         finally:
  221.             source.dnd_end(target, event)
  222.  
  223.  
  224.  
  225.  
  226. class Icon:
  227.     
  228.     def __init__(self, name):
  229.         self.name = name
  230.         self.canvas = None
  231.         self.label = None
  232.         self.id = None
  233.  
  234.     
  235.     def attach(self, canvas, x = 10, y = 10):
  236.         if canvas is self.canvas:
  237.             self.canvas.coords(self.id, x, y)
  238.             return None
  239.         
  240.         if self.canvas:
  241.             self.detach()
  242.         
  243.         if not canvas:
  244.             return None
  245.         
  246.         label = Tkinter.Label(canvas, text = self.name, borderwidth = 2, relief = 'raised')
  247.         id = canvas.create_window(x, y, window = label, anchor = 'nw')
  248.         self.canvas = canvas
  249.         self.label = label
  250.         self.id = id
  251.         label.bind('<ButtonPress>', self.press)
  252.  
  253.     
  254.     def detach(self):
  255.         canvas = self.canvas
  256.         if not canvas:
  257.             return None
  258.         
  259.         id = self.id
  260.         label = self.label
  261.         self.canvas = None
  262.         self.label = None
  263.         self.id = None
  264.         canvas.delete(id)
  265.         label.destroy()
  266.  
  267.     
  268.     def press(self, event):
  269.         if dnd_start(self, event):
  270.             self.x_off = event.x
  271.             self.y_off = event.y
  272.             (self.x_orig, self.y_orig) = self.canvas.coords(self.id)
  273.         
  274.  
  275.     
  276.     def move(self, event):
  277.         (x, y) = self.where(self.canvas, event)
  278.         self.canvas.coords(self.id, x, y)
  279.  
  280.     
  281.     def putback(self):
  282.         self.canvas.coords(self.id, self.x_orig, self.y_orig)
  283.  
  284.     
  285.     def where(self, canvas, event):
  286.         x_org = canvas.winfo_rootx()
  287.         y_org = canvas.winfo_rooty()
  288.         x = event.x_root - x_org
  289.         y = event.y_root - y_org
  290.         return (x - self.x_off, y - self.y_off)
  291.  
  292.     
  293.     def dnd_end(self, target, event):
  294.         pass
  295.  
  296.  
  297.  
  298. class Tester:
  299.     
  300.     def __init__(self, root):
  301.         self.top = Tkinter.Toplevel(root)
  302.         self.canvas = Tkinter.Canvas(self.top, width = 100, height = 100)
  303.         self.canvas.pack(fill = 'both', expand = 1)
  304.         self.canvas.dnd_accept = self.dnd_accept
  305.  
  306.     
  307.     def dnd_accept(self, source, event):
  308.         return self
  309.  
  310.     
  311.     def dnd_enter(self, source, event):
  312.         self.canvas.focus_set()
  313.         (x, y) = source.where(self.canvas, event)
  314.         (x1, y1, x2, y2) = source.canvas.bbox(source.id)
  315.         dx = x2 - x1
  316.         dy = y2 - y1
  317.         self.dndid = self.canvas.create_rectangle(x, y, x + dx, y + dy)
  318.         self.dnd_motion(source, event)
  319.  
  320.     
  321.     def dnd_motion(self, source, event):
  322.         (x, y) = source.where(self.canvas, event)
  323.         (x1, y1, x2, y2) = self.canvas.bbox(self.dndid)
  324.         self.canvas.move(self.dndid, x - x1, y - y1)
  325.  
  326.     
  327.     def dnd_leave(self, source, event):
  328.         self.top.focus_set()
  329.         self.canvas.delete(self.dndid)
  330.         self.dndid = None
  331.  
  332.     
  333.     def dnd_commit(self, source, event):
  334.         self.dnd_leave(source, event)
  335.         (x, y) = source.where(self.canvas, event)
  336.         source.attach(self.canvas, x, y)
  337.  
  338.  
  339.  
  340. def test():
  341.     root = Tkinter.Tk()
  342.     root.geometry('+1+1')
  343.     Tkinter.Button(command = root.quit, text = 'Quit').pack()
  344.     t1 = Tester(root)
  345.     t1.top.geometry('+1+60')
  346.     t2 = Tester(root)
  347.     t2.top.geometry('+120+60')
  348.     t3 = Tester(root)
  349.     t3.top.geometry('+240+60')
  350.     i1 = Icon('ICON1')
  351.     i2 = Icon('ICON2')
  352.     i3 = Icon('ICON3')
  353.     i1.attach(t1.canvas)
  354.     i2.attach(t2.canvas)
  355.     i3.attach(t3.canvas)
  356.     root.mainloop()
  357.  
  358. if __name__ == '__main__':
  359.     test()
  360.  
  361.